package org.example.service;

/**
 * @BelongsProject: Dynamic-relationship-binding
 * @BelongsPackage: org.example.service
 * @Author: dengxiyan
 * @CreateTime: 2025/07/04  10:54
 * @Description: 动态关系管理器
 * @Version: 1.0
 */

import org.example.config.RelationConfig;
import org.example.dao.RelationMetadataRepository;
import org.example.model.BaseEntity;
import org.example.model.RelationMetadata;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

@Service
public class DynamicRelationManager {


    @Autowired
    private RelationMetadataRepository relationMetadataRepo;

    @Autowired
    private RelationConfig relationConfig;

    @PersistenceContext
    private EntityManager entityManager;

    // 关系缓存: sourceClass -> {fieldName -> RelationDefinition}
    private final Map<Class<?>, Map<String, RelationConfig.RelationDefinition>> relationCache = new ConcurrentHashMap<>();


    /**
     * 获取实体类的所有关系定义
     */
    public Map<String, RelationConfig.RelationDefinition> getRelationDefinitions(Class<?> entityClass) {
        return relationCache.get(entityClass);
    }

    /**
     * 根据实体类名获取对应的服务
     */
    @Autowired
    private ApplicationContext applicationContext;

    public EntityService<?> getServiceForEntity(String entityName) {
        String serviceName = Character.toLowerCase(entityName.charAt(0)) +
                entityName.substring(1) + "Service";
        return (EntityService<?>) applicationContext.getBean(serviceName);
    }

    @PostConstruct
    public void init() {
        // 初始化关系缓存
        for (RelationConfig.RelationDefinition rd : relationConfig.getConfig()) {
            try {
                Class<?> sourceClass = Class.forName("org.example.model." + rd.getSource());
                relationCache
                        .computeIfAbsent(sourceClass, k -> new HashMap<>())
                        .put(rd.getSourceField(), rd);
            } catch (ClassNotFoundException e) {
                throw new RuntimeException("实体类未找到: " + rd.getSource(), e);
            }
        }
    }

    // 添加关系
    @Transactional
    public void addRelation(Object source, Object target) {
        Class<?> sourceClass = source.getClass();
        Map<String, RelationConfig.RelationDefinition> fieldMap = relationCache.get(sourceClass);

        if (fieldMap == null) return;

        for (Map.Entry<String, RelationConfig.RelationDefinition> entry : fieldMap.entrySet()) {
            String fieldName = entry.getKey();
            RelationConfig.RelationDefinition rd = entry.getValue();
            Class<?> targetClass;
            try {
                targetClass = Class.forName("org.example.model." + rd.getTarget());
            } catch (ClassNotFoundException e) {
                continue;
            }

            if (!targetClass.isInstance(target)) continue;

            // 处理不同关系类型
            switch (rd.getType()) {
                case "ONE_TO_MANY":
                    handleOneToMany(source, target, rd, fieldName);
                    break;
                case "MANY_TO_ONE":
                    handleManyToOne(source, target, rd);
                    break;
                case "MANY_TO_MANY":
                    handleManyToMany(source, target, rd);
                    break;
            }
        }
    }

    private void handleOneToMany(Object source, Object target, RelationConfig.RelationDefinition rd, String fieldName) {
        try {
            // 获取源实体的集合字段
            Field sourceField = source.getClass().getDeclaredField(fieldName);
            sourceField.setAccessible(true);

            // 获取或初始化集合
            Collection<Object> collection = (Collection<Object>) sourceField.get(source);
            if (collection == null) {
                collection = new ArrayList<>();
                sourceField.set(source, collection);
            }

            // 添加到集合
            collection.add(target);

            // 设置反向关联
            Field targetField = target.getClass().getDeclaredField(rd.getTargetField());
            targetField.setAccessible(true);
            targetField.set(target, source);

            // 保存到中间表
            RelationMetadata rm = new RelationMetadata();
            rm.setSourceEntity(source.getClass().getSimpleName());
            rm.setSourceId(((BaseEntity) source).getId());
            rm.setTargetEntity(target.getClass().getSimpleName());
            rm.setTargetId(((BaseEntity) target).getId());
            rm.setRelationType(rd.getType());
            relationMetadataRepo.save(rm);

        } catch (Exception e) {
            throw new RuntimeException("处理ONE_TO_MANY关系失败", e);
        }
    }

    private void handleManyToOne(Object source, Object target, RelationConfig.RelationDefinition rd) {
        try {
            // 设置源实体的目标字段
            Field sourceField = source.getClass().getDeclaredField(rd.getSourceField());
            sourceField.setAccessible(true);
            sourceField.set(source, target);

            // 保存到中间表
            RelationMetadata rm = new RelationMetadata();
            rm.setSourceEntity(source.getClass().getSimpleName());
            rm.setSourceId(((BaseEntity) source).getId());
            rm.setTargetEntity(target.getClass().getSimpleName());
            rm.setTargetId(((BaseEntity) target).getId());
            rm.setRelationType(rd.getType());
            relationMetadataRepo.save(rm);

        } catch (Exception e) {
            throw new RuntimeException("处理MANY_TO_ONE关系失败", e);
        }
    }

    private void handleManyToMany(Object source, Object target, RelationConfig.RelationDefinition rd) {
        // 保存到中间表
        RelationMetadata rm = new RelationMetadata();
        rm.setSourceEntity(source.getClass().getSimpleName());
        rm.setSourceId(((BaseEntity) source).getId());
        rm.setTargetEntity(target.getClass().getSimpleName());
        rm.setTargetId(((BaseEntity) target).getId());
        rm.setRelationType(rd.getType());
        relationMetadataRepo.save(rm);
    }

    // 删除关系
    @Transactional
    public void removeRelation(Object source, Object target) {
        Long sourceId = ((BaseEntity) source).getId();
        Long targetId = ((BaseEntity) target).getId();
        String sourceEntity = source.getClass().getSimpleName();
        String targetEntity = target.getClass().getSimpleName();

        relationMetadataRepo.deleteBySourceEntityAndSourceIdAndTargetEntityAndTargetId(
                sourceEntity, sourceId, targetEntity, targetId
        );
    }

    private boolean hasField(Class<?> clazz, String fieldName) {
        try {
            clazz.getDeclaredField(fieldName);
            return true;
        } catch (NoSuchFieldException e) {
            return false;
        }
    }

    // 加载实体的关联关系
    @Transactional(readOnly = true)
    public void loadRelations(Object entity) {
        Class<?> entityClass = entity.getClass();
        Map<String, RelationConfig.RelationDefinition> fieldMap = relationCache.get(entityClass);

        if (fieldMap == null) return;

        Long entityId = ((BaseEntity) entity).getId();
        String entityName = entityClass.getSimpleName();

        for (Map.Entry<String, RelationConfig.RelationDefinition> entry : fieldMap.entrySet()) {
            String fieldName = entry.getKey();
            RelationConfig.RelationDefinition rd = entry.getValue();

            try {
                // 跳过不存在的字段（可能是另一侧的关系）
                if (!hasField(entityClass, fieldName)) {
                    continue;
                }
                Field field = entityClass.getDeclaredField(fieldName);
                field.setAccessible(true);

                if (rd.getType().equals("ONE_TO_MANY") || rd.getType().equals("MANY_TO_MANY")) {
                    // 只加载当前实体作为源的关系
                    List<RelationMetadata> relations = relationMetadataRepo
                            .findBySourceEntityAndSourceId(entityName, entityId);

                    List<Object> relatedEntities = new ArrayList<>();
                    for (RelationMetadata rm : relations) {
                        Class<?> targetClass = Class.forName("com.example.demo.entity." + rm.getTargetEntity());
                        Object targetEntity = entityManager.find(targetClass, rm.getTargetId());
                        if (targetEntity != null) {
                            relatedEntities.add(targetEntity);
                        }
                    }

                    // 根据目标字段的实际类型创建集合
                    Collection<Object> collection;

                    if (field.getType().isAssignableFrom(Set.class)) {
                        collection = new HashSet<>();
                    } else {
                        collection = new ArrayList<>(); // 默认使用ArrayList
                    }

                    // 获取现有集合或创建新集合
                    Collection<Object> existing = (Collection<Object>) field.get(entity);
                    if (existing == null) {
                        field.set(entity, collection);
                    } else {
                        collection = existing;
                    }

                    collection.clear();
                    collection.addAll(relatedEntities);

                } else if (rd.getType().equals("MANY_TO_ONE")) {
                    // 只加载当前实体作为目标的关系
                    List<RelationMetadata> relations = relationMetadataRepo
                            .findByTargetEntityAndTargetId(entityName, entityId);

                    if (!relations.isEmpty()) {
                        RelationMetadata rm = relations.get(0);
                        Class<?> sourceClass = Class.forName("com.example.demo.entity." + rm.getSourceEntity());
                        Object sourceEntity = entityManager.find(sourceClass, rm.getSourceId());
                        field.set(entity, sourceEntity);
                    }
                }

            } catch (Exception e) {
                throw new RuntimeException("加载关系失败: " + fieldName, e);
            }
        }
    }



    // 分页查询实体的关联对象
    @Transactional(readOnly = true)
    public Page<Object> findRelatedEntities(Object entity, String relationField, Pageable pageable) {
        Class<?> entityClass = entity.getClass();
        Long entityId = ((BaseEntity) entity).getId();
        String entityName = entityClass.getSimpleName();

        Map<String, RelationConfig.RelationDefinition> fieldMap = relationCache.get(entityClass);
        if (fieldMap == null || !fieldMap.containsKey(relationField)) {
            return Page.empty();
        }

        RelationConfig.RelationDefinition rd = fieldMap.get(relationField);
        Page<RelationMetadata> relationPage;

        if (rd.getType().equals("ONE_TO_MANY") || rd.getType().equals("MANY_TO_MANY")) {
            relationPage = relationMetadataRepo.findBySourceEntityAndSourceId(
                    entityName, entityId, pageable);
        } else {
            relationPage = relationMetadataRepo.findByTargetEntityAndTargetId(
                    entityName, entityId, pageable);
        }

        return relationPage.map(rm -> {
            try {
                String targetEntityName = rd.getType().equals("MANY_TO_ONE") ?
                        rm.getSourceEntity() : rm.getTargetEntity();
                Class<?> targetClass = Class.forName("org.example.model." + targetEntityName);
                Long targetId = rd.getType().equals("MANY_TO_ONE") ?
                        rm.getSourceId() : rm.getTargetId();
                return entityManager.find(targetClass, targetId);
            } catch (ClassNotFoundException e) {
                return null;
            }
        });
    }



}